package oss

import (
	"context"
	"io"
	"io/ioutil"
	"log"
	"strconv"
	"time"

	"gitee.com/les49/esgo/os/file"
	"github.com/minio/minio-go/v7"
	"github.com/minio/minio-go/v7/pkg/credentials"
	"github.com/zeromicro/go-zero/core/logx"
)

const (
	ossTempDir = "/tmp/oss/"
)

type MinioConfig struct {
	Endpoint        string
	AccessKeyId     string
	SccessKeySecret string
}

type OssMinio struct {
	client *minio.Client
}

func NewMinio(c *MinioConfig) *OssMinio {
	client, err := minio.New(c.Endpoint, &minio.Options{Creds: credentials.NewStaticV4(c.AccessKeyId, c.SccessKeySecret, "")})
	if err != nil {
		log.Fatalf("error: new minio, %s %s", c.Endpoint, err.Error())
		return nil
	}
	return &OssMinio{
		client: client,
	}
}

func (o *OssMinio) PutObject(bucketName, objectName string, fileContent []byte) error {
	if !o.ExistBucket(bucketName) {
		opts := minio.MakeBucketOptions{
			Region: "cn-yunan-km",
		}
		o.client.MakeBucket(context.Background(), bucketName, opts)
	}

	filename := ossTempDir + strconv.FormatInt(time.Now().UnixMilli(), 10)
	localFile, err := file.Create(filename)
	if err != nil {
		logx.Error(err.Error())
		return err
	}
	defer localFile.Close()
	defer file.Remove(filename)

	_, err = localFile.Write(fileContent)
	if err != nil {
		logx.Error(err.Error())
		return err
	}
	localFile.Seek(0, io.SeekStart)

	_, err = o.client.PutObject(context.Background(), bucketName, objectName, localFile, int64(len(fileContent)), minio.PutObjectOptions{})
	if err != nil {
		return err
	}

	return nil
}

func (o *OssMinio) GetObject(bucketName, objectName string) ([]byte, error) {
	reader, err := o.client.GetObject(context.Background(), bucketName, objectName, minio.GetObjectOptions{})
	if err != nil {
		return nil, err
	}
	defer reader.Close()

	fileContent, err := ioutil.ReadAll(reader)
	if err != nil {
		return nil, err
	}

	return fileContent, nil
}

func (o *OssMinio) DelObject(bucketName, objectName string) error {
	opts := minio.RemoveObjectOptions{
		GovernanceBypass: true,
	}
	err := o.client.RemoveObject(context.Background(), bucketName, objectName, opts)
	if err != nil {
		return err
	}

	return nil
}

func (o *OssMinio) ExistBucket(bucketName string) bool {
	exist, err := o.client.BucketExists(context.Background(), bucketName)
	if err != nil {
		return false
	}
	return exist
}

func (o *OssMinio) ExistObject(bucketName, objectName string) bool {
	_, err := o.client.StatObject(context.Background(), bucketName, objectName, minio.StatObjectOptions{})
	if err != nil {
		return false
	}

	return true
}
